using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LS.GameKit.Behaviour;
using System.Linq;

namespace LS.GameKit
{
    public abstract class Physics2DBehaviour : PhysicsBehaviour
    {
        public bool castTrigger = true;
        public bool castCollision = true;
        public LayerMask castLayers = new LayerMask();

        [SerializeField]
        private Collider2D m_Collider;

        [SerializeField]
        private Rigidbody2D m_Rigidbody;

        protected Dictionary<Collider2D, PhysicsBehaviourResult> m_ColliderMap = new Dictionary<Collider2D, PhysicsBehaviourResult>();

        public override Transform CachedTransform
        {
            get
            {
                if (m_Rigidbody != null) return m_Rigidbody.transform;
                if (m_Collider != null) return m_Collider.transform;
                return transform;
            }
        }

        public override Vector3 Position
        {
            get
            {
                if (m_Rigidbody != null) return m_Rigidbody.position;
                return transform.position;
            }

            set
            {
                if (m_Rigidbody != null)
                {
                    m_Rigidbody.position = value;
                    return;
                }
                transform.position = value;
            }
        }

        public override Vector3 LocalPosition
        {
            get
            {
                if (m_Rigidbody != null) return
                        transform.parent.InverseTransformPoint(m_Rigidbody.position);
                return transform.localPosition;
            }
            set
            {
                if (m_Rigidbody != null)
                {
                    m_Rigidbody.position = transform.parent.TransformPoint(value);
                    return;
                }
                transform.localPosition = value;
            }
        }

        public override Quaternion Rotation
        {
            get
            {
                if (m_Rigidbody != null) 
                    return Quaternion.Euler(0,0, m_Rigidbody.rotation);
                return transform.rotation;
            }

            set
            {
                if(m_Rigidbody != null)
                {
                    var eular = Quaternion.Angle(Quaternion.identity, value);
                    Vector2 up = value * Vector2.up;
                    if (Vector2.Dot(Vector2.up, up) < 0)
                    {
                        eular = -eular;
                    }
                    m_Rigidbody.rotation = eular;
                    return;
                }
                transform.rotation = value;
            }
        }

        public override Quaternion LocalRotation
        {
            get
            {
                return transform.localRotation;
            }

            set
            {
                if (m_Rigidbody != null)
                {
                    var ro = transform.parent.rotation * value;
                    var eular = Quaternion.Angle(Quaternion.identity, ro);
                    Vector2 up = ro * Vector2.up;
                    if (Vector2.Dot(Vector2.up, up) < 0)
                    {
                        eular = -eular;
                    }
                    m_Rigidbody.rotation = eular;
                    return;
                }
                transform.localRotation = value;
            }
        }

        protected override void OnDisable()
        {
            var kva = m_ColliderMap.ToArray();
            for (int i = 0; i < kva.Length; i++)
            {
                ExitResult(kva[i].Key, kva[i].Value);
            }
            base.OnDisable();
        }

        public override void Translate(Vector3 delta)
        {
            if(m_Rigidbody != null)
            {
                m_Rigidbody.MovePosition(Position + delta);
                return;
            }
            transform.position += delta;
        }

        public override void TranslateLocal(Vector3 delta)
        {
            if(m_Rigidbody != null)
            {
                var pos = transform.localPosition + delta;
                transform.parent.TransformPoint(pos);
                m_Rigidbody.MovePosition(pos);
                return;
            }
            transform.localPosition += delta;
        }

        public override void Rotate(Quaternion delta)
        {
            if (m_Rigidbody != null)
            {
                var rotate = transform.rotation * delta;
                m_Rigidbody.MoveRotation(rotate);
                return;
            }

            transform.rotation *= delta;
        }

        public override void RotateLocal(Quaternion delta)
        {
            if (m_Rigidbody != null)
            {
                var rotate = transform.parent.rotation * (transform.localRotation * delta);
                m_Rigidbody.MoveRotation(rotate);
                return;
            }
            transform.localRotation *= delta;
        }

        public override void RotateEular(Vector3 delta)
        {
            Quaternion rotation = Quaternion.Euler(delta);
            Rotate(rotation);
        }

        public override void RotateLocalEular(Vector3 delta)
        {
            Quaternion rotation = Quaternion.Euler(delta);
            RotateLocal(rotation);
        }

        public override bool ContainsCollider(Collider collider)
        {
            return false;
        }

        public override bool ContainsCollider(Collider2D collider)
        {
            return this.m_Collider == collider;
        }

        public Collider2D[] GetAllInsideColliders()
        {
            return m_ColliderMap.Keys.ToArray();
        }

        public PhysicsBehaviourResult[] GetAllPhysicsResults()
        {
            return m_ColliderMap.Values.ToArray();
        }

        protected virtual void EnterResult(Collider2D collider, PhysicsBehaviourResult result)
        {
            if (m_ColliderMap.TryGetValue(collider, out var r))
            {
                return;
            }
            m_ColliderMap.Add(collider, result);
            OnEnterEvent.Invoke(result);
        }

        protected virtual void UpdateResult(Collider2D collider, PhysicsBehaviourResult result)
        {
            OnUpdateEvent.Invoke(result);
        }

        protected virtual void ExitResult(Collider2D collider, PhysicsBehaviourResult result)
        {
            if (m_ColliderMap.TryGetValue(collider, out var r))
            {
                m_ColliderMap.Remove(collider);
                OnExitEvent.Invoke(r);
            }
        }

        protected PhysicsBehaviourResult FindResult(Collider2D col)
        {
            if (m_ColliderMap.TryGetValue(col, out var result)) return result;
            return null;
        }

        protected PhysicsBehaviourResult FindResult(Collision2D col)
        {
            if (m_ColliderMap.TryGetValue(col.collider, out var result)) return result;
            return null; 
        }

    }
}
